package com.bayair.doctor.mvp;

import android.util.Log;

import com.bayair.doctor.BuildConfig;
import com.bayair.doctor.mvp.proxy.IModelProxy;
import com.bayair.doctor.mvp.proxy.ModelProxyImpl;
import com.bayair.doctor.net.DisposableManager;
import com.bayair.doctor.net.exception.ApiException;
import com.bayair.doctor.net.exception.ApiExceptionHandler;
import com.bayair.doctor.utils.log.KLog;
import com.blankj.utilcode.util.ToastUtils;

import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;

/**
 * 绑定V和P的生命周期，给P层传入V的弱引用
 *
 * @param <V>
 */
public abstract class BasePresenter<V extends IView/*,M extends IModel*/> implements IPresenter<V> {

    public String TAG;

    /**弱引用, 防止内存泄漏*/
    private WeakReference<V> mViewRef;

    private V mProxyView;
    //private M mModel;

    private IModelProxy mMvpProxy;

    protected ModelProxyImpl createModelProxyImpl() {
        return new ModelProxyImpl(this);
    }

    /**
     * 关联V层和P层
     */
    @Override
    public void attachView(V view) {
        mViewRef = new WeakReference<V>(view);

        //动态代理---来决定view层Activity或者Fragment是不是执行view的方法
        MvpViewHandler viewHandler = new MvpViewHandler(mViewRef.get());
        mProxyView = (V) Proxy.newProxyInstance(view.getClass().getClassLoader(), view.getClass().getInterfaces(), viewHandler);

//        /**
//         *  通过获得泛型类的父类，拿到泛型的接口类实列，通过反射来实例化 model
//         */
//        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
//        if (type != null) {
//            //返回一个{@code Type}对象数组，表示该类型的实际类型参数。
//            Type[] types = type.getActualTypeArguments();
//            try {
//                mModel = (M) ((Class<?>) types[1]).newInstance();
//            } catch (IllegalAccessException e) {
//                e.printStackTrace();
//            } catch (InstantiationException e) {
//                e.printStackTrace();
//            }
//        }

        mMvpProxy = createModelProxyImpl();
        mMvpProxy.bindModel();

        //标记，用去传入RxBaseObserver，取消订阅
        TAG = this.getClass().getSimpleName();
    }


    /**
     * @return P层和V层是否关联.
     */
    @Override
    public boolean isViewAttached() {
        return mViewRef != null && mViewRef.get() != null;
    }

    /**
     * 断开V层和P层
     */
    @Override
    public void detachView() {
        //退出页面的时候移除所有网络请求
        DisposableManager.ins().dispose(toString());

        if (isViewAttached()) {
            mViewRef.clear();
            mViewRef = null;
        }
        mMvpProxy.unbindModel();
    }

    public V getView() {
        return mProxyView;
    }

//    protected M getModel() {
//        return getModel();
//    }

    private class MvpViewHandler implements InvocationHandler {
        private IView mvpView;

        MvpViewHandler(IView mvpView) {
            this.mvpView = mvpView;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //如果V层没被销毁, 执行V层的方法.
            if (isViewAttached()) {
                return method.invoke(mvpView, args);
            }
            //P层不需要关注V层的返回值
            return null;
        }
    }

    /**
     * 如果你使用了RxJava,那么请使用本Observer,因为它会自动回收
     */
    public abstract class ObserverOnRecycler<T> implements Observer<T>{

        private final String mName;
        private Disposable d;

        protected ObserverOnRecycler() {
            mName = BasePresenter.this.toString();
        }

        @Override
        public void onSubscribe(Disposable d) {
            this.d = d;
            DisposableManager.ins().onSubscribe(mName, d);
        }

        @Override
        public void onError(Throwable e) {
            DisposableManager.ins().onError(mName, d);
            dispose();

            ApiException apiEx = ApiExceptionHandler.handleException(e);
            if (apiEx.getCode() == 200) {//token过期
                getView().tokenExpire();
            } else {
                toast(apiEx.getMessage());
                log("HTTP请求错误：" + apiEx.getDetailMessage());
            }
        }

        @Override
        public void onComplete() {
            DisposableManager.ins().onComplete(mName, d);
            dispose();
        }

        protected void dispose() {
            if (d != null && !d.isDisposed()) {
                d.dispose();
            }
            d = null;
        }
    }

    /**
     * 显示吐司
     */
    public void toast(CharSequence text) {
        ToastUtils.showShort(text);
    }

    /**
     * 打印日志
     */
    public void log(Object object) {
        KLog.i(getClass().getSimpleName(), object != null ? object.toString() : "null");
    }

    public void loge(Object object) {
        KLog.e(getClass().getSimpleName(), object != null ? object.toString() : "null");
    }
}
